/**
 * 
 * @class NG.response.GetInfoEx
 * @extends NG.response.Response
 * 
 * This data structure is designed as described below;
 * 
 * featureMap=Key:{Info names} Values:{Info} <br>
 * 				   Info={property names}, {InfoDetails} <br>
 * 						InfoDetails={value list} // values are related with Info.propertyNames <br>
 */
NG.response.GetInfoEx = Ext.extend(NG.response.Response, {

	featureMap : new Ext.util.HashMap(),
	
	parseFeatureMember: function(featureData) {

		function findRowsCount(node) {
			var result = 0;
			try {
				if (node.firstElementChild && node.firstElementChild.nodeName === "RowsCount") {
					result = parseInt(node.firstElementChild.textContent);
				}				
			} catch (e) {}
			
			return result;
		}
		
		if (featureData instanceof Text) {
			return null;
		}
		
        if (featureData.childNodes.length == 1 && !(featureData.childNodes[0] instanceof Element)) {
            return null;
        }

        var member = null;
        var childNode = featureData.childNodes[1];
        
        if (!Ext.isDefined(childNode)) { //There does not exist any info
        	return;
        }
        
        if (!this.featureMap.containsKey(childNode.tagName)) {
        	var rowsCount = findRowsCount(childNode);
        	
        	member = new NG.models.Info({
    	        featureMember: childNode.tagName,
    	        rowsCount: rowsCount,
    	        detailList: [],
    	        propertyList: this.getPropertyNames(childNode)
    		});
        	
        	this.featureMap.add(member.getTableDisplayValue(), member);
        }
        
    	member = this.featureMap.get(childNode.tagName);
    	
    	var infodetail = this.getInfoDetail(childNode);
    	
        member.addDetail(infodetail);
        infodetail.setParent(member);
        
        return member;
	},
	
	/**
	 * Parses given xml data and obtains info property names
	 * 
	 * Called by {@link NG.response.GetInfoEx.parseFeatureMember}
	 * @param {String} xmlData - response data
	 */
	getPropertyNames: function(tagData) {
		
		var names = [];
		
		for (var i=0; i<tagData.childNodes.length;++i){
			if (!(tagData.childNodes[i] instanceof Element)){
				continue;
			}
			var tagname = tagData.childNodes[i].tagName;
			
			if (tagname == 'GEOMETRY' || tagname == 'OBJECTID') {
				continue;
			}
				
			names.push(tagData.childNodes[i].tagName);
		}
		
		return names;
	},
	
	/**
	 * Parses given xml data and obtains geometry data
	 * 
	 * Called by {@link NG.response.GetInfoEx.getInfoDetail}
	 * @param {String} xmlData - response data
	 */
	parseGeometry : function(geometry) {
		if (geometry instanceof Text) {
			return null;
		}
		
        if (geometry.childNodes.length == 1 && !(geometry.childNodes[0] instanceof Element)) {
            return null;
        }
		
        var geometryType = geometry.firstElementChild.firstElementChild.firstElementChild;
        
        var geom = null;
        var coords = null;
        if (geometryType.tagName.contains('Polygon')) {
        	geom = new NG.models.NGPolygon();        	
        	coords = geometryType.firstElementChild.firstElementChild.firstElementChild;
        } else if (geometryType.tagName.contains('Point')) {
        	geom = new NG.models.NGPoint();
        	coords = geometryType.firstElementChild;
        } else if (geometryType.tagName.contains('LineString')) {
        	geom = new NG.models.NGLine();
        	coords = geometryType.firstElementChild;
        } else { 
        	return null;
        }
        
    	var unparsedData = null;
    	var decimalDelim = null;
    	var coordinateDelim = null;
    	var positionDelim = null;
    	
		for (var i=0;i<coords.attributes.length;++i) {
			
			if (coords.attributes[i].name == "decimal") {
				decimalDelim = coords.attributes[i].nodeValue;	
			}
			else if (coords.attributes[i].name == "cs") {
				coordinateDelim = coords.attributes[i].nodeValue;	
			}
			else if (coords.attributes[i].name == "ts") {
				positionDelim = coords.attributes[i].nodeValue;
			}
		}
    	
    	geom.setCoordinates(coords.childNodes[0].nodeValue, decimalDelim, coordinateDelim, positionDelim);
    	return geom;
	},
	
	/**
	 * Parses given xml data and obtains info data
	 * 
	 * Called by {@link NG.response.GetInfoEx.parseFeatureMember}
	 * @param {String} xmlData - response data
	 */
	getInfoDetail: function(nodeData) {
		
		var infoDetail = new NG.models.InfoDetail({
											objectID:null, 
											valueList:[], 
											geometryMember:null});
		
		for (var i=0; i<nodeData.childNodes.length;++i){
			
			var childNode = nodeData.childNodes[i];
			
			if (!(childNode instanceof Element)){
				continue;
			}
			
			if (childNode.tagName == 'GEOMETRY') {
				infoDetail.setGeometry(this.parseGeometry(childNode));
			}
			else if (childNode.tagName == 'OBJECTID') {
				infoDetail.setObjectID(childNode.textContent.trim());
			}
			else {
				infoDetail.addValue(childNode.textContent.trim());
			}
		}
		
		return infoDetail;
	},
	
	/**
	 * Parses given xml data
	 * 
	 * Called by {@link NG.response.GetInfoEx.init}
	 * @param {String} xmlData - response data
	 */
	parseXMLData: function (xmlData){
		this.featureMap = new Ext.util.HashMap();
		var xmlStr = fleegix.xml.parse(fleegix.xml.createDoc(xmlData), 'string').string;
		var featureArray = fleegix.xml.createDoc(xmlStr).documentElement;
		var childs = featureArray.childNodes;

		this.featureMap.clear();
		
		for (var i = 0 ; i<childs.length; i++) {
			this.parseFeatureMember(featureArray.childNodes[i]);
		}
	},
	
	/**
	 * Array elements' class is {NG.models.Info}
	 * @returns {Array}
	 */
	getInfoList: function (){
		var infoList = [];
		var keyList = this.featureMap.getKeys();
		
		for (var i=0; i<keyList.length; ++i) {
			infoList.push(this.featureMap.get(keyList[i]));
		}
		return infoList;
	},
	
	constructor: function(config){
		NG.response.GetInfoEx.superclass.constructor.call(this, config);
	},
	
	/**
	 * Parses given xmlData (response data) <br>
	 * Fulfills {NG.response.GetInfoEx} members according to parsed xml data
	 * 
	 * @param {String} xmlData - response data
	 * Called by {@link NG.response.Response.constructor}
	 */
	init: function (xmlData) {
		NG.response.GetInfoEx.superclass.init.call(this, xmlData);
		this.parseXMLData(xmlData);
	}
});
